<script setup lang="ts">
import { useRouter } from "vue-router";
import * as SearchMusicEnum from "@/enums/SearchMusicEnum";
import * as MusicInfoEnum from "@/enums/MusicInfoEnum";
import { formatPlayTime } from "@/utils";
import * as SearchMusicAPi from "@/api/search";
import { ElMessage, ElMessageBox } from "element-plus";
import LoginDialog from "./Model/index.vue";
import HotSearch from "./modules/HotSearch.vue";
import Footer from "./Footer/index.vue";
import { useUserStore } from "@/store/modules/user";
import { useMusicStore } from "@/store/modules/music";
import { storeToRefs } from "pinia";
import { getCurrentInstance, ComponentInternalInstance } from "vue";
import {
  Search,
  CaretRight,
  UserFilled,
  CaretBottom,
  ChatLineSquare,
} from "@element-plus/icons-vue";

const router = useRouter();
const musicStore = useMusicStore();
const { curPlayList } = storeToRefs(musicStore);
const userStore = useUserStore();
const { profile } = storeToRefs(userStore);
// 音乐列表加载
const loading = ref(false);
// 登录dialog组件实例
const LoginDialogRef = ref();
// 搜索建议组件ref
const HotSearchRef = ref();
// 搜索音乐请求参数
const queryParams = reactive({
  // 总搜索数量
  total: 0,
  // 一次返回20条数据
  limit: 20,
  // 偏移量，用于分页
  offset: 0,
  // 页码
  pageNum: 1,
  // 搜索关键字
  keywords: "",
  // 搜索的音乐类型，默认搜索单曲
  type: SearchMusicEnum.SearchMusicType.single,
});
// 表格数据
const table = reactive({
  // 表格数据
  data: [],
  // 表格头部数据
  columns: [
    {
      label: "音乐标题",
      text: "music_name",
      minWidth: 200,
    },
    {
      label: "歌手",
      text: "singer",
    },
    {
      label: "时长",
      text: "music_time",
    },
    {
      label: "热度",
      text: "pop",
      minWidth: 60,
    },
  ] as Array<TableColumnData>,
});
// 当前鼠标右击音乐信息
const curRowMusic = ref<any>({});
// 右键菜单是否可见
const actionVisble = ref(false);
// 弹窗显示的位置
const rect = reactive({
  left: 0,
  top: 0,
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
watch(actionVisble, (value) => {
  if (value) {
    document.body.addEventListener("click", () => (actionVisble.value = false));
  } else {
    document.body.removeEventListener(
      "click",
      () => (actionVisble.value = false)
    );
  }
});

onMounted(() => {
  // 颜色主题
  document.documentElement.style.setProperty("--el-color-primary", "#f5222d");
});

// 输入文字搜索音乐
const handleSearch = (e: KeyboardEvent | Event): any => {
  // 只响应回车事件
  if ((e as KeyboardEvent).key != "Enter") return;
  if (!queryParams.keywords) return;
  HotSearchRef.value?.show(false, queryParams.keywords);
  handleRefresh();
};

// 搜素音乐
function getSearchMusic() {
  // 开始加载
  loading.value = true;
  // 获取搜索歌曲
  SearchMusicAPi.searchMusic({
    keywords: queryParams.keywords,
    limit: queryParams.limit,
    offset: queryParams.offset,
    type: queryParams.type,
  })
    .then((res) => {
      const { code, result } = res.data;
      if (code != 200) {
        return ElMessage.error("搜索失败");
      }
      queryParams.total = result?.songCount || 0;
      table.data = result?.songs || [];
      console.log("搜素音乐成功==>", result);
    })
    .catch((err) => {
      console.log("搜索失败==>", err);
      ElMessage.error(err.message || "搜索失败");
    })
    .finally(() => {
      loading.value = false;
    });
}

// 鼠标右键打开操作菜单，当某一行被鼠标右键点击时会触发该事件
const handleOpenActionMenu = (row: any, column: any, event: MouseEvent) => {
  event.preventDefault();
  // console.log("鼠标右键打开操作菜单==>", row, column, event);
  curRowMusic.value = row;
  openMenu(event);
};

function openMenu(e: MouseEvent) {
  // 弹窗的最小宽度
  const menuMinWidth = 120;
  // 鼠标右键评论项距离视口左侧的距离
  const offsetLeft = proxy?.$el.parentElement?.getBoundingClientRect().left;
  // 鼠标右键评论项的宽度width
  const offsetWidth = proxy?.$el.offsetWidth;
  const maxLeft = offsetWidth - menuMinWidth;
  const l = e.clientX - offsetLeft + 30;

  if (l > maxLeft) {
    rect.left = maxLeft;
  } else {
    rect.left = l;
  }
  rect.top = e.pageY + 5;
  actionVisble.value = true;
}

/**
 * 查看歌曲评论
 */
const handleShowMusicComment = () => {
  play(curRowMusic.value);
  musicStore.showMusicDetail = true;
};

/**
 * 右键播放该音乐
 * @description 首先判断这一首歌在存不存在播放列表中，存在：则直接通过playIndex播放该首音乐，不存在则添加到当前播放音乐的下一首歌曲位置
 */
const handlePlay = () => {
  // some符合一项条件返回true的则返回true
  play(curRowMusic.value);
};

/**
 * 将该音乐设置为下一首播放
 * @description 首先判断这一首歌在存不存在播放列表中，存在：则将这首歌先删除，再移动到当前播放音乐的下一首歌曲位置
 * 不存在：则直接添加到当前播放音乐的下一首歌曲位置
 */
const handleNextPlay = () => {
  // 歌曲不存在当前播放的音乐列表中，获取当前播放下标
  const index = Number(musicStore.playIndex);
  // 要播放的音乐存在于当前音乐播放列表中
  if (hasMusic(curRowMusic.value)) {
    curPlayList.value.forEach((item, i) => {
      if (item.id === curRowMusic.value.id) {
        // 先删除原歌曲所在的位置
        curPlayList.value.splice(i, 1);
        // 再重新追加到当前播放音乐的下一首歌曲位置
        curPlayList.value.splice(index + 1, 0, curRowMusic.value);
      }
    });
  } else {
    // 当前播放列表没有歌曲，直接追加
    if (index == -1 && curPlayList.value.length == 0) {
      curPlayList.value.push(curRowMusic.value);
      return musicStore.setCurMusicRecord(curRowMusic.value, 0);
    }
    // 该歌曲不在当前播放的音乐列表中，直接追加到当前播放音乐的下一首歌曲位置
    curPlayList.value.splice(index + 1, 0, curRowMusic.value);
  }
};

/**
 * 播放音乐公共函数
 */
function play(curRecord: any) {
  // 要播放的音乐存在于当前音乐播放列表中
  if (hasMusic(curRecord)) {
    curPlayList.value.forEach((item, index) => {
      if (item.id === curRecord.id) {
        // 通过下标直接播放该歌曲
        musicStore.setMusic(index);
      }
    });
  } else {
    // 歌曲不存在当前播放的音乐列表中，获取当前播放下标
    const index = Number(musicStore.playIndex);
    // 当前播放列表没有歌曲，直接追加
    if (index == -1 && curPlayList.value.length == 0) {
      curPlayList.value.push(curRecord);
      return musicStore.setCurMusicRecord(curRecord, 0);
    }
    curPlayList.value.forEach((item, i) => {
      if (i === index) {
        curPlayList.value.splice(i + 1, 0, curRecord);
        musicStore.setMusic(i + 1);
      }
    });
  }
}

/**
 * 当前音乐播放列表是否存在该首音乐
 * @returns {Boolean} true存在 false不存在
 */
function hasMusic(record: any): boolean {
  return curPlayList.value.some((item: any) => item.id === record.id);
}

// 在搜素 Input 值改变时触发
function handleSearchInput(value: string | number) {
  debouncedFn(value);
}

/**
 * 音乐搜索防抖
 */
const debouncedFn = useDebounceFn(
  (value) => {
    handleSearchSuggest(value);
  },
  500,
  { maxWait: 5000 }
);

// 搜素建议
function handleSearchSuggest(value: string | number) {
  if(!value) return;
  HotSearchRef.value?.show(true, value);
}

// 双击歌曲列表某一行
const handleDbClickMusicItem = (row: any) => {
  console.log("双击歌曲列表某一行Single==>", row);
  play(row);
};

// 显示搜索建议
const showSuggest = () => {
  if (!queryParams.keywords) return;
  HotSearchRef.value?.show(true, queryParams.keywords);
};

// 点击搜索建议的某一项
const handleClickSuggestItem = () => {
  // 刷新列表
  handleRefresh();
}

// 清空搜索关键字
const handleClearVal = () => {
  queryParams.keywords = '';
  HotSearchRef.value?.show(false, '');
}

// 用户点击头像登录
const handleLogin = () => {
  // 打开弹窗
  LoginDialogRef.value!.show(true);
};

// 分页事件触发回调
const handlePagination = (val: any) => {
  // 分页参数
  queryParams.offset = (val.page - 1) * val.limit;
  // 重新获取数据
  handleRefresh();
};

/**
 * 注销退出登录
 */
function logout() {
  ElMessageBox.confirm("确定要退出嘛?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(() => {
    userStore.logout().then(() => {
      musicStore.reset();
    });
  });
}

// 刷新
function handleRefresh(bool: boolean = true) {
  bool && getSearchMusic();
}

defineOptions({
  name: "Music",
});
</script>

<template>
  <div class="music">
    <div class="m-top">
      <div class="logo flex items-center">
        <img class="w-15 h-15" src="@/assets/logo.png" />
        <span class="ml-3 text-6 text-white font-bold">网易云音乐</span>
      </div>

      <el-dropdown trigger="click" :disabled="profile.isLogin">
        <div class="avatar cursor-pointer">
          <!-- 已登录头像 -->
          <el-avatar
            v-if="profile.avatarUrl"
            :src="profile?.avatarUrl + '?param=40y40'"
          />

          <!-- 未登录头像 -->
          <span
            v-else
            @click.stop="handleLogin"
            class="flex items-center justify-center"
          >
            <el-avatar :size="35" :icon="UserFilled" />
          </span>

          <div class="user-name flex items-center">
            <span class="ml-1 text-xs truncate">{{
              profile.nickname ? profile.nickname : "未登录"
            }}</span>
            <el-icon size="1rem"><CaretBottom /></el-icon>
          </div>
        </div>

        <template #dropdown>
          <el-dropdown-item @click="logout">退出</el-dropdown-item>
        </template>
      </el-dropdown>
    </div>

    <div class="music-wrap">
      <div class="search relative mb-50px">
        <el-input
          v-model="queryParams.keywords"
          style="width: 100%"
          clearable
          size="large"
          placeholder="来搜索些好听的音乐吧"
          :suffix-icon="Search"
          @focus="showSuggest"
          @keydown="handleSearch"
          @input="handleSearchInput"
          @clear="handleClearVal"
        />

        <!-- 搜索建议 -->
        <hot-search ref="HotSearchRef" v-model="queryParams.keywords" @suggestItem="handleClickSuggestItem" />
      </div>

      <div class="music-table">
        <el-table
          stripe
          row-key="id"
          v-loading="loading"
          element-loading-text="加载歌曲中..."
          style="width: 100%"
          empty-text="数据都跑空啦~"
          :data="table.data"
          highlight-current-row
          :header-cell-style="getRowClass"
          @row-contextmenu="handleOpenActionMenu"
          @row-dblclick="handleDbClickMusicItem"
        >
          <!-- 索引列 -->
          <el-table-column
            type="index"
            align="center"
            label="序号"
            width="100"
          />
          <el-table-column
            :align="item.text != 'music_name' ? 'center' : 'left'"
            v-for="(item, index) in table.columns"
            :key="index"
            :label="item.label"
            :prop="item.prop"
            :width="item.width"
            :min-width="item.minWidth"
          >
            <template #default="{ row }">
              <!-- 音乐名称 -->
              <div
                class="flex items-center flex-wrap"
                v-if="item.text === 'music_name'"
              >
                <!-- 音乐名称 -->
                <div
                  class="truncate cursor-pointer mr-4px"
                  :title="row.name"
                  :class="{ 'w-180px': row.name.length > 20 }"
                >
                  {{ row.name }}
                </div>

                <!-- 歌曲别名 -->
                <div
                  v-if="row.alia.length"
                  class="text-xs text-[rgb(188,188,188)] truncate mr-10px"
                >
                  <span
                    class="cursor-pointer"
                    :title="alia"
                    v-for="alia in row.alia"
                    :key="alia"
                    >（{{ alia }}）</span
                  >
                </div>

                <!-- vip音乐标签 -->
                <el-tag
                  class="music-tag vip"
                  v-if="MusicInfoEnum.MusicFeeTypeEnum.VIP == row.fee"
                  >VIP</el-tag
                >
                <!-- 高品质音乐标签 -->
                <el-tag
                  class="music-tag hi-res"
                  v-if="MusicInfoEnum.MusicQualityEnum.HIRES == row.h?.sr"
                  >Hi-Res</el-tag
                >
                <!-- 无损音乐SQ -->
                <el-tag
                  class="music-tag sq"
                  v-if="MusicInfoEnum.MusicQualityEnum.SQ == row.sq?.sr"
                  >SQ</el-tag
                >
                <!-- 是否存在mv -->
                <div
                  class="music-tag mv flex items-center justify-center cursor-pointer"
                  v-if="row.mv !== 0"
                >
                  MV<el-icon><CaretRight /></el-icon>
                </div>
              </div>

              <!-- 歌手名称（可能存在多个歌手） -->
              <div v-if="item.text === 'singer'" class="truncate">
                <span
                  class="singer cursor-pointer"
                  v-if="row.ar.length"
                  v-for="singer in row.ar"
                  :key="singer.id"
                  :title="singer.name"
                >
                  {{ singer.name }}
                </span>
              </div>

              <!-- 音乐时长 -->
              <div v-if="item.text === 'music_time'">
                {{ formatPlayTime(row.dt) }}
              </div>

              <!-- 歌曲热度 -->
              <div v-if="item.text === 'pop'">
                <el-progress
                  color="#C4C4C5"
                  :percentage="row?.pop"
                  :show-text="false"
                  :stroke-width="7"
                />
              </div>

              <!-- 展示其他不需要处理的项 -->
              <div v-if="item.prop != undefined">
                {{ row[item.prop] ?? "暂无数据" }}
              </div>
            </template>
          </el-table-column>
        </el-table>

        <!-- 分页组件 -->
        <pagination
          class="my-30px"
          :total="queryParams.total"
          v-model:limit="queryParams.limit"
          v-model:page="queryParams.pageNum"
          @pagination="handlePagination"
        />

        <!-- 鼠标右键显示操作弹窗 -->
        <div
          v-show="actionVisble"
          class="action-menu"
          :style="{ left: rect.left + 'px', top: rect.top + 'px' }"
        >
          <div class="action flex items-center" @click="handleShowMusicComment">
            <el-icon><ChatLineSquare /></el-icon>
            <span class="ml-[10px]">查看评论(Comment)</span>
          </div>

          <div class="action flex items-center" @click="handlePlay">
            <el-icon><ChatLineSquare /></el-icon>
            <span class="ml-[10px]">播放(Play)</span>
          </div>

          <div class="action flex items-center" @click="handleNextPlay">
            <el-icon><ChatLineSquare /></el-icon>
            <span class="ml-[10px]">下一首播放(Next Play)</span>
          </div>
        </div>
      </div>
    </div>

    <login-dialog ref="LoginDialogRef" />
    <Footer />
  </div>
</template>

<style lang="scss" scoped>
@mixin justify-center {
  display: flex;
  justify-content: center;
}

@mixin align-center {
  display: flex;
  align-items: center;
}

@mixin flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}
.music {
  width: 100%;
  height: auto;
  min-width: 1150px;

  @include justify-center;
  flex-direction: column;
  .m-top {
    position: sticky;
    top: 0;
    z-index: 2;
    width: 100%;
    height: 100px;
    padding: 0 30px;
    // background-color: #f5222d;
    background-color: #ea3e3c;
    // display: grid;
    // grid-template-columns: 1fr 150px;
    @include align-center;
    justify-content: space-between;
    .avatar {
      @include align-center;
      .user-name {
        width: 85px;
        color: #c5c5c5;
        &:hover {
          color: #fff;
        }
      }
    }
    .logo {
      @include flex-center;
    }
  }
}

.music-wrap {
  // position: relative;
  z-index: 1;
  width: 100%;
  padding: 5vh 13em 10vh;
  .search {
    // position: sticky;
    // top: 100px;
    // z-index: 2;
    width: 100%;
    @include justify-center;
  }
}

:deep(.search) {
  .el-input__inner::placeholder {
    // text-align: center;
  }
}

// 每个歌手后面都加一个 “/”，最后一个除外
.singer {
  &:not(:last-child)::after {
    content: "/";
    padding: 0 5px;
  }
}

.music-tag {
  border-radius: 2px;
  margin-left: 5px;
  font-size: 12px;
  height: 15px;
  font-weight: 700;
  padding: 0 2px;
  font-family: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
}
// vip歌曲标签
.vip {
  color: rgb(247, 135, 92);
  border: 1.8px solid rgb(247, 135, 92);
}
// 高品质音乐标签和无损音乐和视频mv标签
.hi-res,
.sq,
.mv {
  color: var(--el-color-primary);
  border: 1.8px solid var(--el-color-primary);
}

.action-menu {
  position: absolute;
  z-index: 99;
  font-size: 12px;
  padding: 10px 0;
  background: var(--el-bg-color-overlay);
  border-radius: 4px;
  box-shadow: var(--el-box-shadow-light);
  .action {
    padding: 8px 16px;
    cursor: pointer;
    &:hover {
      background: var(--el-fill-color-light);
    }
  }
}
</style>
